#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>
    
#define RECV_OK    0
#define RECV_EOF  -1
#define NON_RESERVED_PORT 5001

/* char *sys_errlist[]; */

/* Macros to convert from integer to net byte order and vice versa */
#define i_to_n(n)  (int) htonl( (u_long) n)
#define n_to_i(n)  (int) ntohl( (u_long) n)

main(argc,argv)
int argc;
char *argv[];
{

    if (argc == 2)
    {
	printf("calling client\n");
	client(argv[1]);
	printf("back from client\n");
    }
    else
    {
	printf("calling server\n");
	server();
	printf("back from server\n");
    }
}

server()
{
int rc, ssocket, sfd;

    setup_to_accept(5, NON_RESERVED_PORT, &ssocket);
    for (;;)
    {
	sfd = accept_connection(ssocket);
	if ((rc = fork()) == -1)
	{
	    printf("server: fork failed\n");
	    exit(99);
	}
	else if (rc)
	{
	    close(sfd);
	}
	else
	{
	    close(ssocket);
	    serve_one_connection(sfd);
	    exit(0);
	}
    }
}

serve_one_connection(sfd)
{
int rc;
char buf[100];

    rc = recv_msg(sfd, buf);	
    while (rc == RECV_OK)
    {
	printf("serve_one_connection: received %s \n",buf);
	strcpy(buf,"ack_from_server");
	send_msg(sfd, buf, strlen(buf)+1);
	rc = recv_msg(sfd, buf);	
    }
    close(sfd);
}

client(server_host)
char *server_host;
{
int cfd;
char buf[100];

    cfd = connect_to_server(server_host,NON_RESERVED_PORT);
    while (gets(buf) != NULL)
    {
	send_msg(cfd, buf, strlen(buf)+1);
	recv_msg(cfd, buf);	
	printf("client received %s \n",buf);
    }
}

setup_to_accept(backlog, port, skt)	
int backlog;
int port;
int *skt;
{
int rc;
struct sockaddr_in sin, from;

    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = INADDR_ANY;
    sin.sin_port = htons(port);

    *skt = socket(AF_INET, SOCK_STREAM, 0);
    error_check(*skt,"net_setup_anon_listener socket");

    rc = bind(*skt, (struct sockaddr *)&sin ,sizeof(sin));
    error_check(rc,"net_setup_listener bind");

    rc = listen(*skt, backlog);
    error_check(rc,"net_setup_listener listen");
}

int accept_connection(skt)	
int skt;
{
struct sockaddr_in from;
int fromlen;
int skt2;
int gotit;

    fromlen = sizeof(from);
    gotit = 0;
    while (!gotit)
    {
	skt2 = accept(skt, (struct sockaddr *) &from, &fromlen);
	if (skt2 == -1)
	{
	    if (errno == EINTR)
		continue;
	    else
		error_check(skt2, "accept_connection accept");
	}
	else
	    gotit = 1;
    }

    return(skt2);
}

connect_to_server(hostname, port)	
char *hostname;
int port;
{
int s;
struct sockaddr_in listener;
struct hostent *hp;
int rc;

    hp = gethostbyname(hostname);
    if (hp == NULL)
    {
	printf("connect_to_server: gethostbyname %s: %s -- exiting\n",
		hostname, sys_errlist[errno]);
	exit(99);
    }

    bzero((void *)&listener, sizeof(listener));
    bcopy((void *)hp->h_addr, (void *)&listener.sin_addr, hp->h_length);
    listener.sin_family = hp->h_addrtype;
    listener.sin_port = htons(port);

    s = socket(AF_INET, SOCK_STREAM, 0);
    error_check(s, "net_connect_to_server socket");

    rc = connect(s,(struct sockaddr *) &listener, sizeof(listener));
    error_check(rc, "net_connect_to_server connect");

    return(s);
}

int recv_msg(fd, buf)
int fd;
char *buf;
{
int n;

    n = read(fd, buf, 999);
    error_check(n, "recv_msg read");
    if (n == 0)
	return(RECV_EOF);
    return(RECV_OK);
}

send_msg(fd, buf, size)	
int fd;
char *buf;
int size;
{
int n;

    n = write(fd, buf, size);
    error_check(n, "send_msg write");
}

error_check(val, str)	
int val;
char *str;
{
    if (val < 0)
    {
	printf("%s :%d: %s\n", str, val, sys_errlist[errno]);
	exit(1);
    }
}
